﻿using NPOI.HSSF.Util;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using SimpleExcel.Core.Attributes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace SimpleExcel.Core
{
    public class ExcelCore
    {

        /// <summary>
        /// 格式化字符
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="property"></param>
        /// <returns></returns>
        private static string FormatterValue(object obj,PropertyInfo property)
        {
            var val = property.GetValue(obj);
            if (val == null)
                return "";

            var excelColumnAttr = property.GetCustomAttributes(false).First() as ExcelColumnAttribute;
            if (string.IsNullOrWhiteSpace(excelColumnAttr.Formatter))
                return val.ToString();

            if (val is DateTime)
                return ((DateTime)val).ToString(excelColumnAttr.Formatter);

            return val.ToString();
        }

        /// <summary>
        /// 初始化标题
        /// </summary>
        /// <param name="workbook"></param>
        /// <param name="sheet"></param>
        /// <param name="properties"></param>
        private static void InitTitle(IWorkbook workbook ,ISheet sheet,List<PropertyInfo> properties)
        {
            var headStyle = workbook.CreateCellStyle();
            headStyle.Alignment = HorizontalAlignment.Center;
            headStyle.BorderBottom = BorderStyle.Thin;
            headStyle.BorderLeft = BorderStyle.Thin;
            headStyle.BorderRight = BorderStyle.Thin;
            headStyle.BorderTop = BorderStyle.Thin;

            var headFont = workbook.CreateFont();
            headFont.IsBold = true;
            headStyle.SetFont(headFont);

            var row = sheet.CreateRow(0);
      
            for (int columnIndex = 0; columnIndex < properties.Count; columnIndex++)
            {
                var column = row.CreateCell(columnIndex);
                column.CellStyle = headStyle;

                var property = properties[columnIndex];
                var excelColumnAttr = property.GetCustomAttributes(false).First() as ExcelColumnAttribute;
                column.SetCellValue(excelColumnAttr.Title);

                if (excelColumnAttr.Width > 0)
                    sheet.SetColumnWidth(columnIndex, excelColumnAttr.Width * 256 + 200);
                else
                    sheet.AutoSizeColumn(columnIndex); // 自动列宽

                         
            }
        }

        private static IWorkbook InitWorkBook<T>(List<T> values)
        {
            Type type = typeof(T);

            IWorkbook workbook = new XSSFWorkbook();
            ISheet sheet1 = workbook.CreateSheet("Sheet1");

            // 获取对应的属性，并排序
            var properties = type.GetProperties().Where(c => c.GetCustomAttributes(false)?.FirstOrDefault(f => f is ExcelColumnAttribute) != null).ToList();
            if (properties.Count <= 0)
                throw new ArgumentOutOfRangeException("未找到任何要转换的属性");

            // 排序
            properties = properties.OrderBy(c => (c.GetCustomAttributes(false).First() as ExcelColumnAttribute).OrderBy).ToList();

            // 标题
            InitTitle(workbook, sheet1, properties);

            for (int rowIndex = 1; rowIndex <= values.Count; rowIndex++)
            {
                IRow row = sheet1.CreateRow(rowIndex);
                var item = values[rowIndex - 1];

                for (int columnIndex = 0; columnIndex < properties.Count; columnIndex++)
                {
                    var property = properties[columnIndex];

                    var column = row.CreateCell(columnIndex);
                    column.SetCellValue(FormatterValue(item,property));
                }
            }

            return workbook;
        }


        /// <summary>
        /// 获取excel内存流
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="values"></param>
        /// <returns></returns>
        public static MemoryStream ToMemoryStream<T>(List<T> values)
        {

            IWorkbook workbook = InitWorkBook(values);

            MemoryStream memoryStream = new MemoryStream();
            workbook.Write(memoryStream);
            return memoryStream;
        }
    }
}
